﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Windows.Forms;
using System.Windows.Input;

namespace LegtionMVVM
{
    internal class EventManager
    {
        public static void AddCheckPropertyValueChangedEventToControl(ToBindControl component)
        {
            EventInfo[] events = component.Events;
            if (events != null && events.Length > 0)
            {
                foreach (KeyValuePair<string,string> item in component.BindingDataScriptList)
                {
                    //跳过不支持的模式。
                    if (component.BindingSourceList[item.Key].BindingMode == BindingMode.OneWayD2C)
                        continue;

                    string keyName = item.Key + "Changed";
                    EventInfo temp = component.Type.GetEvent(keyName);
                    if (temp == null)
                    {
                        foreach (EventInfo eventInfo in events)
                        {
                            if (eventInfo.Name.ToLower() == item.Key + "Changed".ToLower())
                            {
                                temp = eventInfo;
                                break;
                            }
                        }
                    }
                    if (temp != null)
                    {
                        temp.AddEventHandler(component.Component,
                            EventHandlerConverter.Convert((EventHandler)Events.SetPropertyDataToViewModel, temp.EventHandlerType));
                    }                 
                }
            }
        }
    }
    internal class Events
    {
        public static void SetPropertyDataToViewModel(object sender, EventArgs e)
        {

        }
    }
    internal static class Guard
    {
        public static void ArgumentNotNull(object argumentValue, string argumentName)
        {
            if (argumentValue == null)
            {
                throw new ArgumentNullException(argumentName);
            }
        }
    }

    internal static class EventHandlerConverter
    {
        public static bool IsValidEventHandler(Type eventHandlerType, out ParameterInfo[] parameters)
        {
            Guard.ArgumentNotNull(eventHandlerType, "eventHandlerType");
            if (!typeof(Delegate).IsAssignableFrom(eventHandlerType))
            {
                parameters = new ParameterInfo[0];
                return false;
            }

            MethodInfo invokeMethod = eventHandlerType.GetMethod("Invoke");
            if (invokeMethod.ReturnType != typeof(void))
            {
                parameters = new ParameterInfo[0];
                return false;
            }
            parameters = invokeMethod.GetParameters();
            if (parameters.Length != 2 || parameters[0].ParameterType != typeof(object))
            {
                return false;
            }
            if (!typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType))
            {
                return false;
            }
            return true;
        }

        //public static Delegate Convert(Delegate eventHandler, Type eventHandlerType)
        //{
        //    Guard.ArgumentNotNull(eventHandler, "eventHandler");
        //    Guard.ArgumentNotNull(eventHandlerType, "eventHandlerType");

        //    ParameterInfo[] destinationParameters;
        //    if (!IsValidEventHandler(eventHandlerType, out destinationParameters))
        //    {
        //        throw new InvalidOperationException();
        //    }

        //    if (eventHandler.GetType() == eventHandlerType)
        //    {
        //        return eventHandler;
        //    }

        //    ParameterInfo[] sourceParameters;
        //    if (!IsValidEventHandler(eventHandler.GetType(), out sourceParameters))
        //    {
        //        throw new InvalidOperationException();
        //    }
        //    Type[] paramTypes = new Type[destinationParameters.Length + 1];
        //    paramTypes[0] = eventHandler.GetType();
        //    for (int i = 0; i < destinationParameters.Length; i++)
        //    {
        //        paramTypes[i + 1] = destinationParameters[i].ParameterType;
        //    }
        //    DynamicMethod method = new DynamicMethod("WrappedEventHandler", null, paramTypes);
        //    MethodInfo invoker = paramTypes[0].GetMethod("Invoke");
        //    ILGenerator il = method.GetILGenerator();
        //    il.Emit(OpCodes.Ldarg_0);
        //    il.Emit(OpCodes.Ldarg_1);
        //    il.Emit(OpCodes.Ldarg_2);
        //    if (!sourceParameters[1].ParameterType.IsAssignableFrom(destinationParameters[1].ParameterType))
        //    {
        //        il.Emit(OpCodes.Castclass, sourceParameters[1].ParameterType);
        //    }
        //    il.Emit(OpCodes.Call, invoker);
        //    il.Emit(OpCodes.Ret);
        //    return method.CreateDelegate(eventHandlerType, eventHandler);
        //}
        public static Delegate Convert(Delegate eventHandler, Type eventHandlerType)
        {
            Guard.ArgumentNotNull(eventHandler, "eventHandler");
            Guard.ArgumentNotNull(eventHandlerType, "eventHandlerType");
            return Delegate.CreateDelegate(eventHandlerType, eventHandler.Method);
        }
        public static TDelegate Convert<TDelegate>(Delegate eventHandler)
        {
            return (TDelegate)(object)Convert(eventHandler, typeof(TDelegate));
        }
    }

    //interface ICommand
    //{

    //    void Execute(object parameter);

    //    bool CanExecute(object parameter);

    //    event EventHandler CanExecuteChanged;
    //}
    public class CommandBase : ICommand
    {
        #region ICommand 成员

        public virtual void Execute(object parameter)
        {
        }

        public virtual bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;

        #endregion
        protected void OnCanExecuteChanged(object sender)
        {
            if (CanExecuteChanged != null)
                CanExecuteChanged(sender, new EventArgs());
        }
    }
    public class Command:CommandBase
    {
        Action<object> exec;
        //Func<object, bool> canExec;
        public Command(Action<object> Exec)
        {
            this.exec=Exec;
        }

        public override bool CanExecute(object parameter)
        {
            return true;
        }

        public override void Execute(object parameter)
        {
            if (exec != null) exec(parameter);
        }

        public void OnCanExecuteChanged()
        {
            base.OnCanExecuteChanged(this);
        }
    }
    /// <summary>
    /// 一条命令可以包含多个触发器，并同步触发器可用状态
    /// </summary>
    public class Command2
    {
        /// <summary>
        /// 实例化命令
        /// </summary>
        /// <param name="Description">对命令的描述</param>
        /// <param name="Excution">命令触发事件的执行体</param>
        public Command2(string Description, EventHandler Excution)
        {
            this.TriggerControls = new List<Control>();
            this.TriggerItems = new List<ToolStripItem>();
            this.Description = Description;
            this.ExcutionBody = Excution;
            this._Enabled = true;
        }

        //当前命令的可用状态，不应直接使用
        bool _Enabled;
        /// <summary>
        /// 获取或设置当前命令的可用状态，这将影响所有触发器的Enabled属性
        /// </summary>
        public bool Enabled
        {
            get { return _Enabled; }
            set
            {
                _Enabled = value;
                foreach (Control TriggerControl in TriggerControls)
                { TriggerControl.Enabled = value; }
                foreach (ToolStripItem TriggerItem in TriggerItems)
                { TriggerItem.Enabled = value; }
            }
        }

        //Control类型触发器
        List<Control> TriggerControls;
        //ToolStripItem类型触发器
        List<ToolStripItem> TriggerItems;

        /// <summary>
        /// 注册触发器
        /// </summary>
        /// <param name="TriggerControl">触发器</param>
        public void RegistTrigger(Control TriggerControl)
        {
            this.TriggerControls.Add(TriggerControl);
            TriggerControl.Click += new EventHandler(this.ExcutionShell);
        }
        /// <summary>
        /// 注册触发器
        /// </summary>
        /// <param name="TriggerToolStripItem">触发器</param>
        public void RegistTrigger(ToolStripItem TriggerToolStripItem)
        {
            this.TriggerItems.Add(TriggerToolStripItem);
            TriggerToolStripItem.Click += new EventHandler(this.ExcutionShell);
        }

        //命令执行外壳，用于检验可用状态
        void ExcutionShell(object sender, EventArgs e)
        {
            if (_Enabled) ExcutionBody(sender, e);
        }
        //命令执行主体
        EventHandler ExcutionBody;

        /// <summary>
        /// 显式强制执行命令处理过程，无论Enabled状态如何
        /// </summary>
        public void Excute()
        {
            ExcutionBody(this, new EventArgs());
        }
        /// <summary>
        /// 显式强制执行命令处理过程，无论Enabled状态如何
        /// </summary>
        /// <param name="sender">指定事件的发出者</param>
        /// <param name="e">事件参数</param>
        public void Excute(object sender, EventArgs e)
        {
            ExcutionBody(sender, e);
        }

        /// <summary>
        /// 获取命令描述
        /// </summary>
        public string Description { get; private set; }
 
    }
}
